diff options
| author | Sebastien Castiel <sebastien@castiel.me> | 2024-01-09 08:53:51 -0500 |
|---|---|---|
| committer | Sebastien Castiel <sebastien@castiel.me> | 2024-01-09 08:53:51 -0500 |
| commit | 1b9e624004cfb64135b744f877e5fa87e5810abd (patch) | |
| tree | f1994b7c10d98410bdc73ca323d2c32e6e019bac /src/app/groups/[groupId] | |
| parent | 6bd3299331265ea2a0c800e3c3199ad4e32ce8de (diff) | |
Ask the user who they are when opening a group for the first time (#7)
Diffstat (limited to 'src/app/groups/[groupId]')
| -rw-r--r-- | src/app/groups/[groupId]/expenses/active-user-modal.tsx | 134 | ||||
| -rw-r--r-- | src/app/groups/[groupId]/expenses/expense-list.tsx | 14 | ||||
| -rw-r--r-- | src/app/groups/[groupId]/expenses/page.tsx | 80 |
3 files changed, 187 insertions, 41 deletions
diff --git a/src/app/groups/[groupId]/expenses/active-user-modal.tsx b/src/app/groups/[groupId]/expenses/active-user-modal.tsx new file mode 100644 index 0000000..5d9d005 --- /dev/null +++ b/src/app/groups/[groupId]/expenses/active-user-modal.tsx @@ -0,0 +1,134 @@ +'use client' + +import { Button } from '@/components/ui/button' +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog' +import { + Drawer, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, +} from '@/components/ui/drawer' +import { Label } from '@/components/ui/label' +import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group' +import { getGroup } from '@/lib/api' +import { useMediaQuery } from '@/lib/hooks' +import { cn } from '@/lib/utils' +import { ComponentProps, useEffect, useState } from 'react' + +type Props = { + group: NonNullable<Awaited<ReturnType<typeof getGroup>>> +} + +export function ActiveUserModal({ group }: Props) { + const [open, setOpen] = useState(false) + const isDesktop = useMediaQuery('(min-width: 768px)') + + useEffect(() => { + const tempUser = localStorage.getItem(`newGroup-activeUser`) + const activeUser = localStorage.getItem(`${group.id}-activeUser`) + if (!tempUser && !activeUser) { + setOpen(true) + } + }, [group]) + + function updateOpen(open: boolean) { + if (!open && !localStorage.getItem(`${group.id}-activeUser`)) { + localStorage.setItem(`${group.id}-activeUser`, 'None') + } + setOpen(open) + } + + if (isDesktop) { + return ( + <Dialog open={open} onOpenChange={updateOpen}> + <DialogContent className="sm:max-w-[425px]"> + <DialogHeader> + <DialogTitle>Who are you?</DialogTitle> + <DialogDescription> + Tell us which participant you are to let us customize how the + information is displayed. + </DialogDescription> + </DialogHeader> + <ActiveUserForm group={group} close={() => setOpen(false)} /> + <DialogFooter className="sm:justify-center"> + <p className="text-sm text-center text-muted-foreground"> + This setting can be changed later in the group settings. + </p> + </DialogFooter> + </DialogContent> + </Dialog> + ) + } + + return ( + <Drawer open={open} onOpenChange={updateOpen}> + <DrawerContent> + <DrawerHeader className="text-left"> + <DrawerTitle>Who are you?</DrawerTitle> + <DrawerDescription> + Tell us which participant you are to let us customize how the + information is displayed. + </DrawerDescription> + </DrawerHeader> + <ActiveUserForm + className="px-4" + group={group} + close={() => setOpen(false)} + /> + <DrawerFooter className="pt-2"> + <p className="text-sm text-center text-muted-foreground"> + This setting can be changed later in the group settings. + </p> + </DrawerFooter> + </DrawerContent> + </Drawer> + ) +} + +function ActiveUserForm({ + group, + close, + className, +}: ComponentProps<'form'> & { group: Props['group']; close: () => void }) { + const [selected, setSelected] = useState('None') + + return ( + <form + className={cn('grid items-start gap-4', className)} + onSubmit={(event) => { + event.preventDefault() + localStorage.setItem(`${group.id}-activeUser`, selected) + close() + }} + > + <RadioGroup defaultValue="none" onValueChange={setSelected}> + <div className="flex flex-col gap-4 my-4"> + <div className="flex items-center space-x-2"> + <RadioGroupItem value="none" id="none" /> + <Label htmlFor="none" className="italic font-normal flex-1"> + I don’t want to select anyone + </Label> + </div> + {group.participants.map((participant) => ( + <div key={participant.id} className="flex items-center space-x-2"> + <RadioGroupItem value={participant.id} id={participant.id} /> + <Label htmlFor={participant.id} className="flex-1"> + {participant.name} + </Label> + </div> + ))} + </div> + </RadioGroup> + <Button type="submit">Save changes</Button> + </form> + ) +} diff --git a/src/app/groups/[groupId]/expenses/expense-list.tsx b/src/app/groups/[groupId]/expenses/expense-list.tsx index ef4903c..4578300 100644 --- a/src/app/groups/[groupId]/expenses/expense-list.tsx +++ b/src/app/groups/[groupId]/expenses/expense-list.tsx @@ -27,11 +27,15 @@ export function ExpenseList({ if (activeUser || newUser) { localStorage.removeItem('newGroup-activeUser') localStorage.removeItem(`${groupId}-newUser`) - const userId = participants.find( - (p) => p.name === (activeUser || newUser), - )?.id - if (userId) { - localStorage.setItem(`${groupId}-activeUser`, userId) + if (activeUser === 'None') { + localStorage.setItem(`${groupId}-activeUser`, 'None') + } else { + const userId = participants.find( + (p) => p.name === (activeUser || newUser), + )?.id + if (userId) { + localStorage.setItem(`${groupId}-activeUser`, userId) + } } } }, [groupId, participants]) diff --git a/src/app/groups/[groupId]/expenses/page.tsx b/src/app/groups/[groupId]/expenses/page.tsx index 5285cb8..2a1ac5f 100644 --- a/src/app/groups/[groupId]/expenses/page.tsx +++ b/src/app/groups/[groupId]/expenses/page.tsx @@ -1,3 +1,4 @@ +import { ActiveUserModal } from '@/app/groups/[groupId]/expenses/active-user-modal' import { ExpenseList } from '@/app/groups/[groupId]/expenses/expense-list' import { Button } from '@/components/ui/button' import { @@ -24,45 +25,52 @@ export default async function GroupExpensesPage({ }: { params: { groupId: string } }) { + const group = await getGroup(groupId) + if (!group) notFound() + return ( - <Card className="mb-4"> - <div className="flex flex-1"> - <CardHeader className="flex-1"> - <CardTitle>Expenses</CardTitle> - <CardDescription> - Here are the expenses that you created for your group. - </CardDescription> - </CardHeader> - <CardHeader> - <Button asChild size="icon"> - <Link href={`/groups/${groupId}/expenses/create`}> - <Plus /> - </Link> - </Button> - </CardHeader> - </div> + <> + <Card className="mb-4"> + <div className="flex flex-1"> + <CardHeader className="flex-1"> + <CardTitle>Expenses</CardTitle> + <CardDescription> + Here are the expenses that you created for your group. + </CardDescription> + </CardHeader> + <CardHeader> + <Button asChild size="icon"> + <Link href={`/groups/${groupId}/expenses/create`}> + <Plus /> + </Link> + </Button> + </CardHeader> + </div> - <CardContent className="p-0"> - <Suspense - fallback={[0, 1, 2].map((i) => ( - <div - key={i} - className="border-t flex justify-between items-center px-6 py-4 text-sm" - > - <div className="flex flex-col gap-2"> - <Skeleton className="h-4 w-16 rounded-full" /> - <Skeleton className="h-4 w-32 rounded-full" /> + <CardContent className="p-0"> + <Suspense + fallback={[0, 1, 2].map((i) => ( + <div + key={i} + className="border-t flex justify-between items-center px-6 py-4 text-sm" + > + <div className="flex flex-col gap-2"> + <Skeleton className="h-4 w-16 rounded-full" /> + <Skeleton className="h-4 w-32 rounded-full" /> + </div> + <div> + <Skeleton className="h-4 w-16 rounded-full" /> + </div> </div> - <div> - <Skeleton className="h-4 w-16 rounded-full" /> - </div> - </div> - ))} - > - <Expenses groupId={groupId} /> - </Suspense> - </CardContent> - </Card> + ))} + > + <Expenses groupId={groupId} /> + </Suspense> + </CardContent> + </Card> + + <ActiveUserModal group={group} /> + </> ) } |
